#ifndef ILI9341_H_
#define ILI9341_H_

#include "board.h"
#include "colors.h"
#include "fonts.h"
#include "image.h"
#include "registers.h"
#include <stdbool.h>

//#define LCD_BL_ON() HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin,
//GPIO_PIN_SET) #define LCD_BL_OFF() HAL_GPIO_WritePin(LCD_BL_GPIO_Port,
//LCD_BL_Pin, GPIO_PIN_RESET)

#define BIT_ADDR(byte_offset, bitnum)                                          \
    (volatile unsigned long *)(0x42000000 + (byte_offset * 32) + (bitnum * 4))


// PC输出对应的字节偏移量为
#define GPIOC_OCTL_OFFSET ((GPIOC + 0x14) - 0x40000000)

// PC输入对应的字节偏移量为
#define GPIOC_ISTAT_OFFSET ((GPIOC + 0x10) - 0x40000000)


// PC输出最终可配置为
#define PCout(n) *(BIT_ADDR(GPIOC_OCTL_OFFSET, n)) // 输出

// PC输入最终可配置为
#define PCin(n) *(BIT_ADDR(GPIOC_ISTAT_OFFSET, n)) // 输入

// PC输出对应的字节偏移量为
#define GPIOD_OCTL_OFFSET ((GPIOD + 0x14) - 0x40000000)

// PC输入对应的字节偏移量为
#define GPIOD_ISTAT_OFFSET ((GPIOD + 0x10) - 0x40000000)


// PC输出最终可配置为
#define PDout(n) *(BIT_ADDR(GPIOD_OCTL_OFFSET, n)) // 输出

// PC输入最终可配置为
#define PDin(n) *(BIT_ADDR(GPIOD_ISTAT_OFFSET, n)) // 输入
    
// 这里的n就是对应的第几位（n取值范围为0-15）。

#define LCD_CS_H PCout(0) = 1;
#define LCD_CS_L PCout(0) = 0;
#define LCD_RS_H PCout(1) = 1;
#define LCD_RS_L PCout(1) = 0;
#define LCD_WR_H PCout(2) = 1;
#define LCD_WR_L PCout(2) = 0;
#define LCD_RD_H PCout(3) = 1;
#define LCD_RD_L PCout(3) = 0;
#define LCD_REST_H PCout(4) = 1;
#define LCD_REST_L PCout(4) = 0;

#define LCD_CONTORL_RCU RCU_GPIOC
#define LCD_CONTORL_PORT GPIOC

#define LCD_CS GPIO_PIN_0
#define LCD_RS GPIO_PIN_1 //数据/指令
#define LCD_WR GPIO_PIN_2
#define LCD_RD GPIO_PIN_3
#define LCD_REST GPIO_PIN_4

#define LCD_DATA_RCU RCU_GPIOE
#define LCD_DATA_PORT GPIOE

//按键
#define KEY_CONTORL_RCU RCU_GPIOD
#define KEY_CONTORL_PORT GPIOD

#define KEY_0_PIN GPIO_PIN_4
#define KEY_1_PIN GPIO_PIN_5
#define KEY_2_PIN GPIO_PIN_6
#define KEY_3_PIN GPIO_PIN_7

#define KEY_0 PDin(4)
#define KEY_1 PDin(5)
#define KEY_2 PDin(6)
#define KEY_3 PDin(7)

#define swap(a, b)                                                             \
    {                                                                          \
        int16_t t = a;                                                         \
        a = b;                                                                 \
        b = t;                                                                 \
    }

#define ILI9341_PIXEL_WIDTH 320
#define ILI9341_PIXEL_HEIGHT 240
#define ILI9341_PIXEL_COUNT ILI9341_PIXEL_WIDTH *ILI9341_PIXEL_HEIGHT

// Any LCD needs to implement these common methods, which allow the low-level
// initialisation and pixel-setting details to be abstracted away from the
// higher level drawing and graphics code.

typedef enum {
    LCD_ORIENTATION_PORTRAIT = 0,
    LCD_ORIENTATION_LANDSCAPE = 1,
    LCD_ORIENTATION_PORTRAIT_MIRROR = 2,
    LCD_ORIENTATION_LANDSCAPE_MIRROR = 3
} lcdOrientationTypeDef;

/**
 * @brief  Draw Properties structures definition
 */
typedef struct {
    uint32_t TextColor;
    uint32_t BackColor;
    sFONT *pFont;
    uint8_t TextWrap;
} lcdFontPropTypeDef;

typedef struct {
    unsigned short x;
    unsigned short y;
} lcdCursorPosTypeDef;

// This struct is used to indicate the capabilities of different LCDs
typedef struct {
    uint16_t width;  // LCD width in pixels (default orientation)
    uint16_t height; // LCD height in pixels (default orientation)
    lcdOrientationTypeDef
        orientation;  // Whether the LCD orientation can be modified
    bool touchscreen; // Whether the LCD has a touch screen
    bool hwscrolling; // Whether the LCD support HW scrolling
} lcdPropertiesTypeDef;

void LCD_IO_Init(void);
void lcdInit(void);
void lcdTest(void);
void lcdFillRGB(uint16_t color);
void lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color);
void lcdDrawHLine(uint16_t x0, uint16_t x1, uint16_t y, uint16_t color);
void lcdDrawVLine(uint16_t x, uint16_t y0, uint16_t y1, uint16_t color);
void lcdDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2,
                 uint16_t color);
void lcdDrawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void lcdDrawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r,
                      uint16_t color);
void lcdDrawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
                         uint16_t color);
void lcdDrawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void lcdDrawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
                     int16_t y2, uint16_t color);
void lcdFillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void lcdFillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
                         int16_t delta, uint16_t color);
void lcdFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
                 uint16_t fillcolor);
void lcdFillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r,
                      uint16_t color);
void lcdFillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2,
                     int16_t y2, uint16_t color);
void lcdDrawImage(uint16_t x, uint16_t y,
                  GUI_CONST_STORAGE GUI_BITMAP *pBitmap);
void lcdHome(void);
void lcdDrawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
                 uint16_t bg);
void lcdPrintf(const char *fmt, ...);
void lcdSetTextFont(sFONT *font);
void lcdSetTextColor(uint16_t c, uint16_t b);
void lcdSetTextWrap(uint8_t w);
void lcdSetOrientation(lcdOrientationTypeDef orientation);
void lcdSetCursor(unsigned short x, unsigned short y);
void lcdSetWindow(unsigned short x0, unsigned short y0, unsigned short x1,
                  unsigned short y1);
void lcdBacklightOff(void);
void lcdBacklightOn(void);
void lcdInversionOff(void);
void lcdInversionOn(void);
void lcdDisplayOff(void);
void lcdDisplayOn(void);
void lcdTearingOff(void);
void lcdTearingOn(bool m);
void ILI9341_WriteData(uint16_t data);

uint16_t lcdGetWidth(void);
uint16_t lcdGetHeight(void);
uint16_t lcdGetControllerID(void);
lcdOrientationTypeDef lcdGetOrientation(void);
sFONT *lcdGetTextFont(void);
lcdPropertiesTypeDef lcdGetProperties(void);
uint16_t lcdReadPixel(uint16_t x, uint16_t y);
uint16_t lcdColor565(uint8_t r, uint8_t g, uint8_t b);

#endif /* ILI9341_H_ */
